import webapp2
import StringIO
import PIL
import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont
import PIL.ImageEnhance
import logging 
import urllib
from google.appengine.api import urlfetch
from google.appengine.api import memcache

import handlers
import flickr
import blogger
import vagasapien

BACKGROUND_SIZE = (1800, 1600)
CACHE_SECONDS = 21600

ENABLE_CACHE = True

class StaticMapHandler(webapp2.RequestHandler):
    def write_image_data(self, image_data, format):
        self.response.headers['Content-Type'] = "image/{}".format(format.lower())
        self.response.out.write(image_data)
    
    def get_image_data(self, image, format, **params):
        image_data = StringIO.StringIO()
        image.save(image_data, format=format.upper(), **params)
        return image_data.getvalue()
    
    def write_error(self, text):
        image = PIL.Image.new("RGB", (600, 400), (255, 255, 255))
        draw = PIL.ImageDraw.Draw(image)
        for n, line in enumerate(["ERROR: ", ] + text.splitlines()):
            draw.text((10, 10 * n + 10), line, fill=(0, 0, 0))
        self.write_image(image, "png")
        logging.error(text)
    
    def apply_filters(self, image):
        if self.query.blur:
            image = image.filter(PIL.ImageFilter.BLUR)
        if self.query.brightness < 1.0:
            enhancer = PIL.ImageEnhance.Brightness(image)
            image = enhancer.enhance(self.query.brightness)
        if self.query.color < 1.0:
            enhancer = PIL.ImageEnhance.Color(image)
            image = enhancer.enhance(self.query.color)
        return image
        
    @property
    def cache_key(self):
        pass
        
    @property
    def image_format(self):
        pass
        
    def write_cached_image_data(self):
        image_data = memcache.get(self.cache_key)
        if image_data:
            self.write_image_data(image_data, self.image_format)
            return True
        return False
    
    def cache_image_data(self, image_data):
        memcache.add(self.cache_key, image_data, CACHE_SECONDS)

    def generate_image(self):
        pass

    def get(self):
        self.query = handlers.Query(self.request)
        self.blog = blogger.Blog(vagasapien.BLOG_URL)
        self.photostream = flickr.Photostream(vagasapien.NSID)
        
        if not self.blog.fix:
            self.write_error("Could not get latitude, longitude fix from blog.")
            return
        
        if ENABLE_CACHE and self.write_cached_image_data():
            return
            
        image = self.generate_image()
        
        image_data = self.get_image_data(image, self.image_format, quality=self.query.quality)
        self.write_image_data(image_data, self.image_format)
        if ENABLE_CACHE:
            self.cache_image_data(image_data)

class BackgroundHandler(StaticMapHandler):
    def generate_map_image(self):
        map_parameters = self.query.get_map_parameters()
        map_parameters['size'] = '640x568'
        map_parameters['scale'] = 2
        map_parameters['sensor'] = "false"
        map_parameters['center'] = str(self.blog.fix.offset(*self.query.offset))
        map_url = handlers.STATIC_MAPS_URL + urllib.urlencode(map_parameters)
        map_response = urlfetch.fetch(map_url)
        map_image = PIL.Image.open(StringIO.StringIO(map_response.content))
        map_image = map_image.convert("RGB")
        map_image = map_image.resize(BACKGROUND_SIZE, PIL.Image.BICUBIC)
        return map_image
    
    def composite_photos(self, image):
        for placement in self.query.get_photo_placements():
            photo = self.photostream.fetch_image(placement.index, placement.size)
            if not photo: continue
            if placement.rotation:
                photo = photo.rotate(placement.rotation, PIL.Image.BICUBIC, True)
                image.paste(photo, (placement.x, placement.y), photo)
        return image
    
    @property
    def cache_key(self):
        return 'background-' + '|'.join((self.query.hash(), str(self.blog.fix), self.photostream.get_photo_id(0)))
    
    @property
    def image_format(self):
        return 'JPEG'
    
    def generate_image(self):
        image = self.generate_map_image()
        image = self.composite_photos(image)
        image = self.apply_filters(image)
        return image
    
class MinimapHandler(StaticMapHandler):
    def generate_map_image(self):
        map_parameters = self.query.get_map_parameters()
        #map_parameters['size'] = '220x220'
        map_parameters['scale'] = 1
        map_parameters['sensor'] = "false"
        map_parameters['center'] = str(self.blog.fix.offset(*self.query.offset))
        
        if self.blog.fix:
            # draw historical route
            route = self.blog.get_route(max_length=self.query.length)
            path = "color:red|weight:5|" + "|".join([str(p) for p in route])
            map_parameters['path'] = path
            
            # marker for current location
            markers = "color:red|" + str(self.blog.fix)
            map_parameters['markers'] = markers
            logging.debug(markers)
        
        map_url = handlers.STATIC_MAPS_URL + urllib.urlencode(map_parameters)
        map_response = urlfetch.fetch(map_url)
        map_image = PIL.Image.open(StringIO.StringIO(map_response.content))
        map_image = map_image.convert("RGB")
        return map_image
    
    @property
    def cache_key(self):
        return 'minimap-' + '|'.join((self.query.hash(), str(self.blog.fix)))
    
    @property
    def image_format(self):
        return 'PNG'
    
    def generate_image(self):
        image = self.generate_map_image()
        image = self.apply_filters(image)
        return image

class ColorHandler(webapp2.RequestHandler):
    def get(self):
        red = int(self.request.get("r") or 0)
        green = int(self.request.get("g") or 0)
        blue = int(self.request.get("b") or 0)
        alpha = int(self.request.get("a") or 0)
        
        
        image = PIL.Image.new("RGBA", (100, 100), (red, green, blue, alpha))
        image_data = StringIO.StringIO()
        image.save(image_data, format='PNG')
        self.response.headers['Content-Type'] = "image/png"
        self.response.out.write(image_data.getvalue())

background = webapp2.WSGIApplication([('/background', BackgroundHandler)], debug=True)
minimap = webapp2.WSGIApplication([('/minimap', MinimapHandler)], debug=True)
color = webapp2.WSGIApplication([('/color', ColorHandler)], debug=True)


